The Let's Play Archive

EXAPUNKS

by Carbon dioxide

Part 31: KGOG-TV

Part 31 - KGOG-TV

=== Trash World Inbox ===

Best scores I got on King's Ransom Online were 37, 30 and 25. Let's see your improvements.

GuavaMoment posted:

code:
XA
GRAB 300
COPY F X
LINK 800
REPL 803
WIPE
REPL 804
LINK 800
NOOP
MARK DEL
GRAB 200
SEEK 2
COPY X F
COPY F T
REPL D2
COPY F T
REPL D2
COPY F T
REPL D2
COPY F T
REPL D2
COPY F T
REPL D2
MARK D2
GRAB T
SEEK 2
COPY X F
COPY F T
DROP
GRAB T
SEEK 2
COPY X F
HALT
MARK 803
REPL 802
REPL 801
LINK 803
JUMP DEL
MARK 804
LINK 804
JUMP DEL
MARK 805
LINK 805
JUMP DEL
MARK 802
REPL 805
LINK 802
JUMP DEL
MARK 801
LINK 801
JUMP DEL

XB
NOOP
LINK 800
REPL 802
LINK 803
KILL
KILL
KILL
MARK 802
LINK 802
KILL
KILL
KILL

XC
LINK 800
REPL 805
REPL 804
LINK 800
KILL
KILL
KILL
MARK 805
REPL 801
LINK 805
KILL
KILL
KILL
MARK 804
LINK 804
KILL
KILL
KILL
MARK 801
LINK 801
KILL
KILL
KILL
All six exas go into their areas simultaneously, then there's a lot of loop unrolling. Create an exa to replace the ID for every file. EXAs die if they reach the end of file, and you only have to check once for sub-sub buildings.
28/85/33. Nice clean solution, XB and XC together make quick work of the foreign EXAs, and XA does the file stuff.

GuavaMoment posted:

Now for low line - 1623/20/25. So we need each exa to go into rooms numbered around 800, and then grab files in the 200s, right? Start at 806 and count down attempting both! Enter every room from from 0 to 806, grab every file from 0 to 806. After thousands upon thousands of exas die, the countdown reaches 0 and die for good. Weapons have a number in the second file spot, so those get excluded.
code:
GRAB 300
LINK 800
COPY F X
WIPE
COPY 806 T
MARK MANY
MODI -1 T T
REPL MANY
LINK T
KILL
KILL
KILL
MARK COPY
MODI -1 T T
REPL COPY
GRAB T
SEEK 1
TEST F > 0
TJMP MANY
COPY X F
The description speaks for itself. I keep forgetting about that MODI -1 T T trick to subtract one and automatically die when it hits zero. Also, the TJMP MANY is just a convenient way to make those EXAs that grabbed a weapon harmless. They'll REPL into something that links nowhere and then T hits zero (since the TEST set it to 1) and it dies.

Finally, let's go back to the elusive 24-activity solution. Both GuavaMoment and I came up with a way to do this. I'll start with my own.

The main difference from my attempt in the previous update is that I now fill the hosts with files instead of EXAs. I found files much easier to control.
I'll add some explanations in the code.
code:
;XA LOCAL

COPY 800 X
LINK X

@REP 5
REPL LINK
ADDI X 1 X
@END

MARK LINK
LINK X

; after getting an EXA in each host, it makes a counter.
REPL COUNTER 

; Then the EXA grabs file 200 and each sub file, copying 1 to local M for each file it's about to grab. This EXA and its repls will die once all files have been handled, dropping the files unchanged. This just counts the buildings.
COPY 200 X

MARK GRABSUBFILE
COPY 1 M
GRAB X
SEEK 3
MARK SUBFILELP
COPY F X
REPL GRABSUBFILE
JUMP SUBFILELP

; In this stage, the counter counts the M's coming from the building EXAs just above. It knows when it's done and jumps out to FILLER once MRD is false. The NOOPs make the timing work out.
MARK COUNTER 
COPY 0 X
MARK NEXTM
NOOP
NOOP
NOOP
TEST MRD
FJMP FILLER
ADDI M X X
JUMP NEXTM

; After the file counting is done, the FILLER creates this Fill 'r up EXA, which sends a message to M (like the file counter), then makes a file, and waits for M to decide if it should drop it or not.
; If it drops it, it'll immediately try again. An EXA will hang on DROP if there's no place to drop the file.
MARK FILLRUP
COPY 1 M
MAKE
TEST M = 0
FJMP ENDFILL
DROP
JUMP FILLRUP

; This is the next part of the counting EXA. After creating Fill 'r up, it starts counting further, similarly to the building counter above. The big difference is it sends 0 to M to tell Fill 'r up to keep going.
; Once MRD is false, we know Fill 'r up is hanging on a DROP and continue.
MARK FILLER
REPL FILLRUP

MARK NEXTDROPM
NOOP
NOOP
TEST MRD
FJMP COUNTDONE
ADDI M X X
COPY 0 M
JUMP NEXTDROPM

; The number of foreign EXAs is simple to calculate: X will contain the number of buildings plus the files that were just created. There's 12 places so we just need to calculate the difference.
; It's off by one because this EXA takes up a spot itself.
MARK COUNTDONE
SUBI 11 X T

; Before killing we need to clean up the mess. Fill 'r up is blocking on DROP while holding a file. We obviously can't use a KILL on it, that would beat the purpose.
; So we just grab file 200 (which always exists), which unblocks Fill 'r up, and lets us send -1, which makes it jump to ENDFILL, where it just WIPEs the file it's holding and then dies.
GRAB 200
VOID M
COPY -1 M
NOOP
NOOP

; Once that's taken care of, KILL the exact number of foreign EXAs.
MARK KILLOOP
KILL
SUBI T 1 T
TJMP KILLOOP

; To leave no evidence we need to WIPE the empty files we created. Turns out their IDs start at 400 and never go above 440 so this can be done with a simple grab-and-wipe loop.
COPY 399 X

MARK CLEANLP
ADDI X 1 X
REPL CLEANER
TEST X > 441
FJMP CLEANLP

; Finally, go to GLOBAL mode to get the player ID from XB, and go through all the files again. Since the EXA is already holding 200 by this point, it skips the GRAB step with a JUMP the first time round.
MODE
JUMP SUBFILE2START

MARK GRABSUBFILE2
GRAB X
MARK SUBFILE2START
SEEK 2
COPY M F

MARK SUBFILELP2
COPY F X
REPL GRABSUBFILE2
JUMP SUBFILELP2

MARK CLEANER
GRAB X
MARK ENDFILL
WIPE

;XB GLOBAL
; XB is the same as before - it tries to send the player id 36 times because that's the max number of buildings we can have.
; It doesn't need a delay loop at the start this time because the XAs will stay in LOCAL mode until they're ready.

GRAB 300
COPY F X

COPY 36 T

MARK LOOP
COPY X M
SUBI T 1 T
TJMP LOOP

;XC GLOBAL
; XC is completely unchanged. It waits however long it takes for XA/XB to be completely done (turns out to be 205 loops in the slowest test),
; then voids whatever M message from XB remain, so it can die of natural causes.

COPY 205 T
MARK LP
SUBI T 1 T
TJMP LP

MARK ENDLOOP
VOID M
NOOP
NOOP
TEST MRD
TJMP ENDLOOP
Video
The end result is 517/100/24. I had to squeeze a little bit to fit it in the 100 size limit but I didn't have to try too hard. I'm pretty sure I could save more lines if I really wanted to.

GuavaMoment posted:

I see you at LINES 100 and I thought the amount of lines was going to be the limiting factor in the solution, so I used my really low line filegrabbing solution as the base. 1823/81/24 There's a LOT of timewasting to get everything synced up. I still try to grab a LOT of non-existent files which wastes more time. Lower any of the timewasting values by even 1 and something breaks.
code:
XA LOCAL

COPY 800 T
LINK 800
@REP 5
REPL LINK
ADDI T 1 T
@END
MARK LINK
LINK T

; all six rooms are filled with one exa

COPY 299 T
REPL FILEGRAB
MARK WAIT1   ;create exas grabbing files 299 on down, and begin WAIT1 until that's done. Each fileholder will send '1' over M.
SUBI T 1 T
TJMP WAIT1
COPY 8 X 
REPL SLOWFILL           ;attempt to fill empty spots with 8 exas as CO2 did. Buuuut there's a delay before each filler is made
	;we want to count all the fillers later before another is created
COPY 0 X
COPY 78 T    
MARK WAIT2    ; and wait2 until everything is filled.
SUBI T 1 T
TJMP WAIT2
ADDI X M X
MARK COUNTLOOP
TEST MRD
FJMP VOIDLOOP
ADDI X M X
JUMP COUNTLOOP        ;count the number of alive exas before more than one is created

MARK VOIDLOOP
COPY 16 T 
MARK WAIT3
SUBI T 1 T
TJMP WAIT3    ;void the extra exas created slower than they're made until no more are being replicated
TEST MRD
FJMP KILLS
VOID M
JUMP VOIDLOOP

MARK KILLS
SUBI 11 X T    ;the real number is 11 minus the count not twelve since one extra is created
; I don't know it just works
MARK KILLING
FJMP DONEKILL
KILL
SUBI T 1 T
JUMP KILLING    ;hey idiot, change this to a TJMP and remove the FJMP DONEKILL line you say - 
Well, I'd do that, but it breaks the solution somehow

MARK DONEKILL
MODE
COPY M X   ;grab the file value from XB
COPY 370 T      ;begin grabbing every file from 370 down to 0. Yes, the files start at 299, 
but this also acts to slow things down and make sure everything times out properly
MARK FILEGRAB2
MODI -1 T T
REPL FILEGRAB2
GRAB T
SEEK 1
TEST F > 0
TJMP LINK
COPY X F

MARK SLOWFILL
MODI -1 X X
REPL FILLER
COPY 16 T    
MARK SLOWWAIT
SUBI T 1 T
TJMP SLOWWAIT
JUMP SLOWFILL

MARK FILEGRAB
MODI -1 T T
REPL FILEGRAB
GRAB T
MARK FILLER
COPY 1 M

-------------------
XB GLOBAL

GRAB 300
COPY F X
COPY 5 T
MARK HERE
COPY X M
MODI -1 T T
JUMP HERE
Ah, so the EXA-filling solution is possible, with patience. The main trick seems to be to slow down the fill so much that between one EXA being created and the next, there's enough time to count all of them. But, that means that when you're actually creating EXAs to fill up the host, or to clean up the remainder of the 8 EXAs that are being created, you have to wait for that slow fill as well.


=== KGOG-TV - Satellite Uplink ===

Oh. They just shut the whole game down.
Something about "hackers" or something?
I guess that means you.
People are taking this so seriously.




Three votes for real money, one for "their loss".

It is real money...

People act like the online world is different, but it really isn't.
At least as far as human behavior goes.






Next up... Ember wants us to upload a tv program? Okay.

You know what really moves people?
Art.




One vote for "That's why art is powerful", but three people didn't like where this was going.

I already don't like where this is going...

I've been working on something creative.
An abstract video piece.
It's an expression of some of the ideas I've been developing around shape, form, and color.
You'll see.
Let's get it out there.


Don't worry too much, Ember just wants her art to be seen. Seeing how recently NFTs gained popularity, I doubt Zach had even heard of them when he made this game.


OST: Behind the Scenes

The assignment:
- Align the satellite dish with the target satellite by setting the azimuth, elevation and frequency. Then transmit the data from EMBER-2's video (file 301) after encrypting it using the TV station's encryption key (file 199).
- The azimuth, elevation, and frequency of the target satellite are available in file 300.
- Note that you must align the satellite dish before transmitting any data.
- For more information see "Look to the Stars with Satellite Uplink Systems" in the second issue of the zine.


Ember, how did you even get us inside a tv transmission satellite dish?

Before I'll grab the zine, it might interest you that K-GOG has the shows "Ten Men and a Dog", "City Livin'", "Cooking for Losers", "Takedown", "Buy it, Love it", and "Futurelook 2000" lined up. Which is your favorite?



Okay, so writing to the motor registers moves the dish, while I can read the current position from the #AZIM and #ELEV registers. The encryption is quite basic as encryption schemes go, add the first value of the data to the first value of the encryption key, modulo 10000. Repeat with the second value of the data and the second value of the encryption key and so on. If there's more data than values in the encryption key, wrap around to the beginning of the key. A complication is be that EXAs are limited to 9999, so I'll need a trick for the modulo operation.

But first, let's get the sat aligned.

code:
GRAB 300
LINK 800
LINK 799
SEEK 1
COPY F X
REPL AZI
SEEK 1
COPY F X
REPL ELEV
SEEK 1
COPY F #FREQ
HALT

MARK AZI
LINK 800
SUBI X #AZIM X
TEST X > 0
TJMP MOVEUP

MARK MOVEDOWN
MODI 1 X X
COPY -1 #MOTR
JUMP MOVEDOWN

MARK ELEV
LINK 801
SUBI X #ELEV X
TEST X > 0
FJMP MOVEDOWN

MARK MOVEUP
MODI -1 X X
COPY 1 #MOTR
JUMP MOVEUP
The EXA reads the azimuth and elevation from file 300 and makes REPLs to handle them. The frequency is easier, it can just be sent to the register right away.

The motors only can move one step at a time. So the azimuth and elevation EXAs calculate the difference between the current value and where they should be, and then either move up and down. The move loops are interwoven so that both the AZI and ELEV only need one conditional jump and can fall through otherwise. And I use the MODI trick GuavaMoment helped me remember to have the EXAs die automatically when they're done.

The uplink status on the top right says "Link: Locked" once all settings are right.

Next up is encrypting the file. To keep the activity as low as possible I think it's best if I send the dish settings over M so I can carry file 301 with me and handle that without a lot of messaging.

Let's go through it step by step.

XB is a simple EXA that grabs file 300, and sends the azimuth, elevation and frequency over M:
code:
GRAB 300
MARK LOOP
SEEK 1
COPY F M
JUMP LOOP
I could unroll that but I don't know how much space I'll have before the end so let's not optimize prematurely.

code:
GRAB 301
LINK 800
REPL ENCRFILE

LINK 799
REPL AZI
REPL ELEV
COPY M #FREQ

[...]

MARK AZI
LINK 800
SUBI M #AZIM X
TEST X > 0
TJMP MOVEUP

MARK MOVEDOWN
MODI 1 X X
COPY -1 #MOTR
JUMP MOVEDOWN

MARK ELEV
LINK 801
SUBI M #ELEV X
TEST X > 0
FJMP MOVEDOWN

MARK MOVEUP
MODI -1 X X
COPY 1 #MOTR
JUMP MOVEUP
XA leaves behind an ENCRFILE EXA in the host that has the encryption key, then makes the azimuth and elevation EXAs. I moved the azimuth/elevation transmission to those EXAs to save a bit of time. It's important that the right EXA gets the right value, and this could easily go wrong here because the frequency, AZI and ELEV EXAs all ask for M around the same cycle. I could prevent that by adding some NOOPs or whatever but the unpredictable order of M's in the same cycle just happens to work out in my favour here.

Let's look at the ENCRFILE EXA next.
code:
MARK ENCRFILE
GRAB 199
COPY 49 T
MARK WAIT
SUBI T 1 T
TJMP WAIT

MARK SENDKEY
COPY F M
DIVI 0 M X
TEST EOF
TJMP RESET
JUMP SENDKEY

MARK RESET
SEEK -9999
JUMP SENDKEY
It grabs the file, then waits a while before it starts sending data. The main reason is because I need to make sure the dish settings are sent first. But, since I had the loop in place already I lengthened it to 49 steps, which ensures that the dish is fully set in each test case. That way, I won't try sending data before the thing is aimed at the satellite.

Anyway, after sending a key value, it waits for an incoming M. To cause this EXA to stop at the end, it dies if M is zero.
Otherwise, it tests if it's at the end of the encryption file and if so starts over from the beginning of the file. Either way it sends the next value and repeats.
code:
MODE
REPL SENDER

SEEK 1
MARK NEXTDATA
COPY F M
TEST EOF
FJMP NEXTDATA

COPY 0 M
MODE
VOID M
COPY 0 M
JUMP DONE
After the 'main' EXA sets the frequency, it switches to local mode, then creates a SENDER EXA that will handle the actual encryption and sending logic. It grabbed the data file along the way, so now it just skips past the video title, then starts sending data locally. At the end of the file, it sends a 0 to let SENDER know it's done, and then switches back to global, voids the next encryption value from ENCRFILE and sends it a 0 (kill signal).

code:
MARK SENDER
MAKE

MARK NEXT
COPY M T
FJMP DONE
COPY T X
MODE
COPY M F
SEEK -1
COPY 1 M
ADDI X F F
SEEK -1
TEST F = 9999
FJMP SENDDIRECT
SEEK -2
SWIZ F 0004 T
SWIZ X 0004 F
SEEK -1
ADDI T F T
SWIZ T 1000 T
SWIZ X 0321 X
ADDI X T T
SEEK -2
SWIZ F 0321 X
ADDI X T #DATA
MODE
JUMP NEXT

MARK SENDDIRECT
SEEK -1
COPY F #DATA
MODE
JUMP NEXT

MARK DONE
WIPE
The sender contains the encryption logic. It makes a temporary file because it has a lot of values to juggle. First thing it does is check if the value from the data EXA is a zero, in which case it stops. Both the data EXA and this one jump to DONE to make sure they don't leave their files in the foreign host.

For the encryption, it first copies the data value to X (I needed it in T to see quickly if it was zero, but I need to free T for an upcoming test). Then the EXA switches to global mode and puts the encryption value in F. It tells the ENCRFILE EXA to get ready to send another message, and adds up the data and encryption values, saving that to the file. If the result is less than 9999, it sends the data right away. Otherwise it needs to do something tricky to get the "modulo 10000" requirement.

The SWIZ 0004 instructions return a number that contains the thousands digit of the original, in the ones place. Those can be added together. For instance, if the result is 15, that means the full result would be 15xxx, modulo 10K makes 5xxx. That's what the SWIZ 1000 does. It takes the digit in the ones place, and puts it in the thousands place. The digit is where it should be and we get the modulo operation for free.
Next I take only the lower three digits of the data and encryption value using SWIZ 0321 instructions, add everything together, and send it to #DATA.



The top percentiles are 180, 56 and 4. I'm not wasting any activity points but there are improvements for the other metrics.

There is in fact a much, much simpler way to implement the encryption algorithm. EXAs do have a range that goes beyond 10000 values - we just need to use it. It's negative numbers, of course.

I can rewrite the whole SENDER code to just this:
code:
MARK SENDER
COPY M X
TEST X = 0
TJMP DONE
SUBI X 9999 X
MODE
ADDI M X X
TEST X < 0
COPY 1 M
TJMP ADD
SUBI X 1 #DATA
MODE
JUMP SENDER

MARK ADD
ADDI 9999 X #DATA
MODE
JUMP SENDER
The data value is stored as 9999 less than the actual value. Then the encryption value is added to it. This will never overflow, since the new total will never be more than 9999.

Now there's two possibilities. Either the result is less than 0 (the total was less than 9999), in which case I can just re-add the 9999 and send to #DATA. Or it's more, in which case we would have to apply the modulo operation. Since that's equivalent to subtracting 10000, and I already subtracted 9999, I just subtract one more and that's it. No more temporary files, everything can be done in-place.

Because it's so much faster, I had to bump ENCRFILE's wait time to 55 loops. This solution clocks in at 431/76/4. Less lines of code and less cycles.

You might've already realized the next step. Since the temporarily file isn't necessary anymore, we can delete the entire dedicated SENDER EXA and have the main data one handle the encryption logic. That skips a lot of M transmissions.
code:
; XA

GRAB 301
LINK 800
REPL ENCRFILE

LINK 799
REPL AZI
REPL ELEV
COPY M #FREQ

SEEK 1
MARK NEXTDATA
TEST EOF
TJMP DONE
SUBI F 9999 X
ADDI M X X
TEST X < 0
COPY 1 M
TJMP ADD
SUBI X 1 #DATA
JUMP NEXTDATA

MARK ADD
ADDI 9999 X #DATA
JUMP NEXTDATA

MARK AZI
LINK 800
SUBI M #AZIM X
TEST X > 0
TJMP MOVEUP

MARK MOVEDOWN
MODI 1 X X
COPY -1 #MOTR
JUMP MOVEDOWN

MARK ELEV
LINK 801
SUBI M #ELEV X
TEST X > 0
FJMP MOVEDOWN

MARK MOVEUP
MODI -1 X X
COPY 1 #MOTR
JUMP MOVEUP

MARK ENCRFILE
GRAB 199
COPY 55 T
MARK WAIT
SUBI T 1 T
TJMP WAIT

MARK SENDKEY
COPY F M
DIVI 0 M X
TEST EOF
TJMP RESET
JUMP SENDKEY

MARK RESET
SEEK -9999
JUMP SENDKEY

MARK DONE
VOID M
WIPE
COPY 0 M

; XB

GRAB 300
MARK LOOP
SEEK 1
COPY F M
JUMP LOOP
360/63/4.

Now that I don't need to worry about activity anymore, I can also get rid of that annoying wait by doing the encryption in parallel with setting the dish.
code:
; XA

GRAB 301
LINK 800
REPL SETDISH

MODE
REPL ENCRFILE

VOID F
MARK NEXTDATA
TEST EOF
TJMP DONE
SUBI F 9999 X
ADDI M X X
SEEK -1
TEST X < 0
TJMP ADD
SUBI X 1 F
JUMP NEXTDATA

MARK ADD
ADDI 9999 X F
JUMP NEXTDATA

MARK AZI
LINK 800
SUBI X #AZIM X
TEST X > 0
TJMP MOVEUP

MARK MOVEDOWN
MODI 1 X X
COPY -1 #MOTR
JUMP MOVEDOWN

MARK ELEV
LINK 801
SUBI X #ELEV X
TEST X > 0
FJMP MOVEDOWN

MARK MOVEUP
MODI -1 X X
COPY 1 #MOTR
JUMP MOVEUP

MARK ENCRFILE
GRAB 199

MARK SENDKEY
COPY F M
TEST EOF
TJMP RESET
JUMP SENDKEY

MARK RESET
SEEK -9999
JUMP SENDKEY

MARK SETDISH
LINK 799
COPY M X
REPL AZI
COPY M X
REPL ELEV
COPY M #FREQ

MARK DONE
KILL
LINK 799
SEEK -9999
@REP 24
COPY F #DATA
@END
WIPE

;XB was unchanged
253/88/7.
While SETDISH does its thing, the ENCRFILE EXA and the data one are sitting in the SECURE host, communicating in local mode. The data EXA overwrites the values in Ember's file with the encrypted values. At the end it kills the ENCRFILE EXA, hops over to the transmitter, and sends all the contents of the file.

I shuffled some code around, mostly to make sure EXAs that are finished fall through into code that makes them stop themselves. The different use of M somehow changed the order the dish EXAs receive the data in so I had to move the COPY M instructions back to the main SETDISH code.

Next, I noticed that the encryption algorithm is still the slowest step by far. The most obvious thing I can remove from it are the two cycles to check EOF. I can't unroll that loop much, I don't have a lot of lines left, but there's another way.
code:
REPL GRABBER

VOID F
MARK NEXTDATA
@REP 2
SUBI F 9999 X
ADDI M X X
SEEK -1
TEST X < 0
TJMP ADD
SUBI X 1 F
@END
JUMP NEXTDATA

MARK ADD
ADDI X 9999 F
JUMP NEXTDATA

[...]

MARK GRABBER
REPL GRAB
NOOP
NOOP
JUMP GRABBER

MARK GRAB
GRAB 301

KILL
KILL

; Take the file to the transmission host and send all the data as before
207/100/7. When the data EXA is at the end of the file it will die, and the GRABBER EXA can take it and send the data. I needed some NOOPs to slow the replication down enough that the KILLs work properly.

In this solution, the encryption algorithm is still the slowest step. It's possible to change that, for instance by writing the raw value to F before checking if it's negative, and handling that later, when sending the data. However, that means you can't fully unroll the sender code anymore with the @REP 24, so you need TEST EOF instructions and everything, and it slows down the whole program significantly.

So, I'll end it today with top scores of 207 cycles and 63 size.

By the way, I hadn't noticed it before but there's some sort of ad in the zine, just after the satellite dish article.



Sounds neat.

Well, what did you think?



The first vote. And for next time...

Okay, no more trying to find shortcuts.
Time for a brute-force solution to the money problem.
I know you like messing around with bank systems...